#include "Image.h"
#include <cstdio>
#include <iostream>
using namespace std;

void Image::operator=(Image& m)
{
    if (data != nullptr)
        del(height, &data);
    height = m.height;
    width = m.width;
    data = arr(height, width);
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k] = m.data[i][k];
}

//取反
void Image::operator-()
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            data[i][j] = 255 - data[i][j];
        }
    }
}


void Image::gray2bw(double t)
{
    if (t < 0 || t > 1)
    {
        cout << "t需要在0~1之间" << endl;
        exit(0);
    }

    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k] > (t * 255) ? data[i][k] = 255 : data[i][k] = 0;

}

Image& Image::operator++()
{
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k]++;
    return *this;
}

Image& Image::operator--()
{
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k]--;
    return *this;
}

Image Image::operator++(int)
{
    Image old(*this);
    ++(*this);
    return old;
}

Image Image::operator--(int)
{
    Image old(*this);
    --(*this);
    return old;
}

void Image::First_to_Secon(unsigned char *da)
{
    unsigned char *p;
    p=da;

    data=new unsigned char*[height];

    for(int i=0;i<height;i++)
    {
        data[i]=new unsigned char[width];
    }

    for(int i = height-1; i >=0; i--)
    {
       for(int j = 0;j < width; j += 3)
       {
           p+=1;
           data[i][j]=*p;
           p+=1;
           data[i][j+1]=*p;
           p+=1;
           data[i][j+2]=*p;
           p+=1;
       }
    }
}

void Image::Secon_to_First(unsigned char* da)
{
    unsigned char *p;
    p=da;

    for(int i = height-1; i >=0; i--)
    {
       for(int j = 0;j < width; j += 3)
       {
          *p= data[i][j];
           p+=1;
          *p=data[i][j+1];
           p+=1;
           *p=data[i][j+2];
           p+=1;
           *p=255;
           p++;
       }
    }
}

Image::Image()
{
    height = 0;
    width = 0;
    data = nullptr;

}

Image::Image(int h, int w)
{
    height = h;
    width = w;
    data = arr(h, w);

}

Image::Image(int h, int w, unsigned char val)
{
    height = h;
    width = w;
    data = arr(h, w, val);


}

void Image::del(int h, unsigned char*** d)
{
    for (int i = 0; i < h; i++)
        delete[](*d)[i];
    delete[](*d);
    *d = nullptr;
}

unsigned char** Image::arr(int h, int w, unsigned char val)
{
    unsigned char** d = new unsigned char* [h];
    for (int i = 0; i < h; i++)
    {
        d[i] = new unsigned char[w];
        for (int k = 0; k < w; k++)
            d[i][k] = val;
    }

    return d;
}

Image::Image(const char* ImageName)
{
    data = nullptr;
    ReadBMP(ImageName);
}

Image::Image(unsigned char m[][100], int n)
{
    height = n;
    width = 100;
    data = arr(n, 100);
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k] = m[i][k];
}

Image::Image(unsigned char** m, int h, int w)
{
    height = h;
    width = w;
    data = arr(h, w);
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k] = m[i][k];
}

Image::Image(Image& im)
{
    height = im.height;
    width = im.width;
    data = arr(height, width);
    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            data[i][k] = im.data[i][k];
    bmpfileheader = im.bmpfileheader;
    bitmapinfoheader = im.bitmapinfoheader;
}

Image::~Image()
{
    del(height, &data);
}

void Image::Flip(int code)
{
    if (code == 0)//左右
    {
        for (int i = 0; i < height; i++)
            for (int k = 0; k < width / 2; k += 3)
            {
                unsigned char ch[3];
                ch[0] = data[i][k];
                ch[1] = data[i][k + 1];
                ch[2] = data[i][k + 2];

                data[i][k]     = data[i][width - k - 3];
                data[i][k + 1] = data[i][width - k - 2];
                data[i][k + 2] = data[i][width - k - 1];

                data[i][width - k - 3] = ch[0];
                data[i][width - k - 2] = ch[1];
                data[i][width - k - 1] = ch[2];
            }
    }

    if (code == 1)//上下
    {
        unsigned char* p;

            for (int i = 0; i < height / 2; i++)
            {
                p = data[i];
                data[i] = data[height - i - 1];
                data[height - i - 1] = p;
            }
    }
}

bool Image::ReadBMP(QString imgname)
{
    FILE* fp;
   std::string str=imgname.toStdString();
   const char* ImageName=str.c_str();
    fopen_s(&fp, ImageName, "rb");

    if (fp == nullptr)
    {
        cout << "文件打开错误" << endl;
       return 0;
    }

    fread(&bmpfileheader, sizeof(bmpfileheader), 1, fp);
    fread(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp);

    if (data != nullptr)
        del(height, &data);

    height = bitmapinfoheader.biHeight;
    width = bitmapinfoheader.biWidth * 3;

    int p = ((width ) % 4 == 0) ? 0 : (4 - (width ) % 4);

    data = arr(height, width);

    for (int i = 0; i < height; i++)
    {
        for (int k = 0; k < width; k++)
        {
            unsigned char c[1];
            fread(c, 1, 1, fp);
            data[i][k] = c[0];

        }
        for (int j = 0; j < p; j++)//吞掉末尾的零
            fgetc(fp);
    }
    fclose(fp);
    return 1;
}


void Image::WriteBMP(QString imgname)
{
    std::string str=imgname.toStdString();
    const char* ImageName=str.c_str();

    FILE* fp = nullptr;
    fopen_s(&fp, ImageName, "wb");

    int p = ((width ) % 4 == 0) ? 0 : (4 - (width ) % 4);

    //文件头
    bmpfileheader.bfType = 0x4d42;
    bmpfileheader.bfSize = 14 + 40 + (width  + p) * height;
    bmpfileheader.bfReserved1 = 0;
    bmpfileheader.bfReserved2 = 0;
    bmpfileheader.bfOffBits = 54;
    fwrite(&bmpfileheader, sizeof(bmpfileheader), 1, fp);


    //信息头
    bitmapinfoheader.biSize = 40;
    bitmapinfoheader.biWidth = width / 3;
    bitmapinfoheader.biHeight = height;
    bitmapinfoheader.biPlanes = 1;
    bitmapinfoheader.biBitCount = 24;
    bitmapinfoheader.biCompression = 0;
    bitmapinfoheader.biSizeImage = (width  + p) * height;
    bitmapinfoheader.biXPelsPerMeter = 0;
    bitmapinfoheader.biYPelsPerMeter = 0;
    bitmapinfoheader.biClrUsed = 0;
    bitmapinfoheader.biClrImportant = 0;
    fwrite(&bitmapinfoheader, sizeof(bitmapinfoheader), 1, fp);

    char ch = 0;


    for (int i = 0; i < height; i++)
    {
        for (int k = 0; k < width; k++)
        {
            if (data[i][k] < 0)data[i][k] = 0;//色素溢出处理
            if (data[i][k] > 255)data[i][k] = 255;
            fwrite(&data[i][k], 1, 1, fp);
        }
        if (p != 0)
            fwrite(&ch, 1, p, fp);
    }

    fclose(fp);
}

void Image::ReadText(const char* Name)
{
    FILE* fp;
    fopen_s(&fp, Name, "rb");

    if (fp == nullptr)
    {
        cout << "文件打开错误" << endl;
        exit(0);
    }

    fread(&height, 4, 1, fp);
    fread(&width, 4, 1, fp);

    data = arr(height, width);

    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            fread(&data[i][k], 1, 1, fp);

    fclose(fp);
}

void Image::WriteText(const char* Name)
{
    FILE* fp;
    fopen_s(&fp, Name, "wb");

    fwrite(&height, 4, 1, fp);
    fwrite(&height, 4, 1, fp);

    for (int i = 0; i < height; i++)
        for (int k = 0; k < width; k++)
            fwrite(&data[i][k], 1, 1, fp);

    fclose(fp);
}

void Image::Cut(int x1, int y2, int x2, int y1)
{
    //图像数据是上下颠倒的，将y1,y2翻过来
    y1 = height - y1;
    y2 = height - y2;

    x1 *= 3;
    x2 *= 3;

    unsigned char** d = arr(y2 - y1, x2 - x1);

    for (int i = y1; i < y2; i++)
        for (int k = x1; k < x2; k += 3)
        {
            d[i - y1][k - x1] = data[i][k];
            d[i - y1][k - x1 + 1] = data[i][k + 1];
            d[i - y1][k - x1 + 2] = data[i][k + 2];
        }


    del(height, &data);
    height = y2 - y1;
    width = x2 - x1;

    data = d;
}

void Image::Rotate(int degree)
{
    int p = degree > 0 ? (degree % 360) : (360 - abs(degree) % 360);

    if (p == 90)//顺时针90
    {
        int temp;
        temp = height;
        height = width / 3;
        width = temp * 3;

        unsigned char** d = arr(height, width);

        for (int i = 0; i < width / 3; i++)
            for (int k = 0; k < height * 3; k += 3)
            {
                d[height - (k + 1) / 3 - 1][3 * i] = data[i][k];
                d[height - (k + 1) / 3 - 1][3 * i + 1] = data[i][k + 1];
                d[height - (k + 1) / 3 - 1][3 * i + 2] = data[i][k + 2];
            }
        del(width / 3, &data);
        data = d;
    }

    //将每一行数据左右逆过来，再调换上下指针
    if (p == 180)//顺时针180
    {
        unsigned char** d = arr(height, width);

        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j += 3)
            {
                d[i][j + 0] = data[i][width - j - 3];
                d[i][j + 1] = data[i][width - j - 2];
                d[i][j + 2] = data[i][width - j - 1];
            }
        }

        for (int i = 0; i < height; i++)
        {
            delete[]data[i];
            data[i] = d[height - i - 1];
        }
    }

    if (p == 270)//顺时针270
    {
        int temp;
        temp = height;
        height = width / 3;
        width = temp * 3;

        unsigned char** d = arr(height, width);

        for (int i = 0; i < width / 3; i++)
            for (int k = 0; k < height * 3; k += 3)
            {
                d[(k + 1) / 3][width - 3 * i - 3] = data[i][k];
                d[(k + 1) / 3][width - 3 * i - 2] = data[i][k + 1];
                d[(k + 1) / 3][width - 3 * i - 1] = data[i][k + 2];
            }
        del(width / 3, &data);
        data = d;
    }
}

void Image::ReadBMPre(const char* ImageName)
{
    ReadBMP(ImageName);

    for(int j = 0;j<height;j++)
     for (int i = 0; i < width ; i += 3)
     {
         unsigned char ch;
         ch = data[j][i] / 3 + data[j][i + 1] / 3 + data[j][i + 2] / 3;
         data[j][i] = data[j][i + 1] = data[j][i + 2] = ch;
     }
}

void Image::Grey_scale()
{
    for(int i=0;i<height;i++)
    {
        for(int j=0;j<width;j+=3)
        {
           unsigned char ch;
           ch=data[i][j]/3+data[i][j+1]/3+data[i][j+2]/3;

           data[i][j]=ch;
           data[i][j+1]=ch;
           data[i][j+2]=ch;
        }
    }
}
void Image::mosaic(int x1, int y2, int x2, int y1)
{
    x1 *= 3;
    x2 *= 3;

    y1 = height - y1;//这里这么处理y1和y2是因为bmp文件的图片数据是左下到右上的
    y2 = height - y2;

    int size = 16;

    //判断输入的值是否正确
    if (x1<0 || x1>width - 1 || x2<0 || x2>width - 1 || y1<0 || y1>height - 1 || y2<0 || y2>height - 1)
    {
        cout << "输入错误" << endl;
        exit(0);
    }

    for (int i = y1; i < y2; i=i+size)
    {
        for (int j = x1; j < x2; j+= size * 3)
        {
            for (int k = i-size/2; k < i + size/2 ; k++)
            {
                for (int q = j - 3 * size / 2; q < j + 3 * size / 2; q += 3)
                {
                    int p;

                    if (k<0 || k>height - 1 || q<0 || q>width - 1)
                        p = 0;
                    else p = 1;

                    if (p == 1)
                    {
                        data[k][q] = data[i][j];
                        data[k][q + 1] = data[i][j + 1];
                        data[k][q + 2] = data[i][j + 2];
                    }
                }
            }

        }
    }
}

unsigned char Image::mean(int x, int y, int size)
{
    int sum = 0;
    double num = 0;
    int p;

    for (int i = y - size / 2; i < y + size / 2 + 1; i++)
    {
        for (int k = x - size / 2 * 3 ; k < x + size / 2 * 3 + 1; k += 3)
        {//这里加三是因为只计算单一通道，保留彩色
            if (i < 0 || i > height - 1 || k < 0 || k > width - 1)
                p = 0;
            else p = 1;

            sum += p;

            if(p != 0)num += data[i][k] * p;
        }
    }

    return (num / sum);
}

unsigned char Image::median(int x, int y, int size)
{
    int p;
    double* array = new double[size * size];//排序用
    int  q = 0;

    for (int i = y - size / 2; i < y + size / 2 + 1; i++)
    {
        for (int k = x - size / 2 * 3; k < x + size / 2 * 3 + 1; k += 3)
        {
            if (i < 0 || i > height - 1 || k < 0 || k > width - 1)//判断该点是否超过矩阵边界
                p = 0;
            else p = 1;

            if (p != 0) array[q++] = data[i][k];
        }
    }


    for (int i = 0; i < q - 1; i++)//冒泡排序
        for (int k = 0; k < q - i - 1; k++)
        {
            double temp;

            if (array[k] > array[k + 1])
            {
                temp = array[k];
                array[k] = array[k + 1];
                array[k + 1] = temp;
            }
        }
    return(array[q / 2]);
}


void Image::compress(int pre)
{
    unsigned char* da[3] = { new unsigned char[height * width * 2 / 3] };

    unsigned char ch;
    int sum = 0, num = 0;
    ch = data[0][0];

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width / 3; j++)
        {
            da[0][sum++] = data[i][j];
            da[1][sum++] = data[i][j+1];
            da[2][sum++] = data[i][j+2];
        }
    }


    cout << "num=" << num << endl;
}

void Image::sharpen()
{
     for (int i = 0; i < height; i++)
     {
        for (int j = 0; j < width; j++)
        {
            unsigned char ch[4];
            int p[4] = { 0 };

            if (i > 0)
            {
                ch[0] = data[i - 1][j]-data[i][j];
                p[0] = 1;
            }
            if (j > 2)
            {
                ch[1] = data[i][j - 3] - data[i][j];
                p[1] = 1;
            }
            if (i < height - 1)
            {
                ch[2] = data[i + 1][j] - data[i][j];
                p[2] = 1;
            }
            if (j < width - 3)
            {
                ch[3] =data[i][j + 3] - data[i][j];
                p[3] = 1;
            }

            data[i][j] = (p[0] * ch[0] + p[1] * ch[1] + p[2] * ch[2] + p[3] * ch[3]) / (p[0] + p[1] + p[2] + p[3]);
        }
     }
}

void Image::sharpenre()
{
    unsigned char** d = arr(height, width);
    double vx, vy;
    for (int i = 1; i < height - 1; i++)
    {
        for (int j = 3; j < width - 3; j++)
        {
            vx = data[i - 1][j - 3] + 2 * data[i][j - 3] + data[i + 1][j - 3] - data[i - 1][j + 3] - 2 * data[i][j + 3] - data[i + 1][j + 3];
            vy = data[i - 1][j - 3] + data[i - 1][j] * 2 + data[i - 1][j + 3] - data[i + 1][j - 3] - data[i + 1][j] * 2 - data[i + 1][j + 3];
            d[i][j] = fabs(vx) + fabs(vy);
        }
    }
    for (int i = 1; i < height - 1; i++)
    {
        for (int j = 1; j < width - 1; j++)
        {
            data[i][j] = d[i][j];
        }
    }

    del(height, &d);
}
void Image::MeanFilter(int size)
{
    unsigned char** d = arr(height, width);/*求均值过程中原图像不应改变
                                           所以先把数据转到另一个数组先*/

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            d[i][j] = mean(j, i, size);
        }
    }

    del(height, &data);
    data = d;
}

void Image::MedianFilter(int size)
{
    unsigned char** d = arr(height, width);/*求中值过程中原图像不应改变
                                           所以先把数据转到另一个数组先*/

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            d[i][j] = median(j, i, size);
        }
    }

    del(height, &data);
    data = d;
}

//color的值,1、2、3分别代表更改R、B、G，0代表RBG都更改
void Image::ChangeRBG(int color, int value)
{
    if (color == 0)
    {
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                data[i][j] += value;
            }
        }
    }
    else if (color == 1||color == 2||color == 3)
    {
        for (int i = 0; i < height; i++)
        {
            for (int j = color -1; j < width; j += 3)
            {
                data[i][j] += value;
            }
        }
    }
}


